/**
 * 
 * 起迪科技 Copyright (c) 2014-2017 QiDi,Inc.All Rights Reserved.
 */
package cn.qidisoft.edu.hzjt.interceptor;

import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import cn.qidisoft.core.common.log.LoggerAdapter;
import cn.qidisoft.core.common.log.LoggerAdapterFactory;
import cn.qidisoft.core.util.StringUtils;
import cn.qidisoft.core.web.customargument.bind.annotation.IfNeedLogin;
import cn.qidisoft.edu.hzjt.constants.Constant;
import cn.qidisoft.edu.hzjt.model.Priority;
import cn.qidisoft.edu.hzjt.model.Student;
import cn.qidisoft.edu.hzjt.model.UserEmployee;
import cn.qidisoft.edu.hzjt.service.ICommonService;
import cn.qidisoft.edu.hzjt.utils.LogType;
import cn.qidisoft.edu.hzjt.utils.SpringUtil;

/**
 * 
 * @author hxq
 * @version $Id: CheckLoginInterceptor.java, v 0.1 2018年3月13日 下午8:39:56 hxq Exp $
 */
public class CheckLoginInterceptor extends HandlerInterceptorAdapter {
  protected static final LoggerAdapter LOGGER =
      LoggerAdapterFactory.getLogger(LogType.HZJT_LOGGER.val);
  private String returnLoginUrl = Constant.REDIRECT_LOGIN_URL;

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    // String requestUrl = request.getRequestURI();
    // if (!requestUrl.equals("/") && !requestUrl.equals("/index")) {
    // if (verfityReferer(request) == false) {
    // response.sendRedirect(returnLoginUrl);
    // return false;
    // }
    // }
    // 判断是否需要验证登陆
    if (handler instanceof HandlerMethod) {
      HandlerMethod handlerMethod = (HandlerMethod) handler;
      Method method = handlerMethod.getMethod();
      IfNeedLogin ifNeedLogin = method.getAnnotation(IfNeedLogin.class);
      if (ifNeedLogin == null) {
        ifNeedLogin = ((HandlerMethod) handler).getBeanType().getAnnotation(IfNeedLogin.class);
      }
      // 需要验证登陆
      if ((ifNeedLogin == null) || ifNeedLogin.needLogin()) {
        String userID = request.getParameter("userid"); // 判断用户ID
        String type = request.getParameter("type"); // 用户类型
        Integer type2 = null;
        boolean bool2 = false;
        if (request.getSession().getAttribute(Constant.LOGIN_CONSOLE_USER) != null
            && request.getSession().getAttribute(Constant.LOGIN_USER_TYPE) != null) {// 标识已经登陆,标识session未过期，那么进行用户身份比对
          Integer sessionType =
              (Integer) request.getSession().getAttribute(Constant.LOGIN_USER_TYPE);
          if (!StringUtils.isNullValue(type) && !StringUtils.isNullValue(userID)) { // 标识从栏目传过来的用户类型
            type2 = type.equals("s") ? 1 : 2;
            if (sessionType.intValue() == type2.intValue()) { // 如果相同，代表session的用户类型与传的用户是同一个用户类型
              boolean bool = isValdateCurentLoginUser(request, type, userID);
              if (bool == false) { // 表示用户信息不相同
                clearSessionUser(request); // 清空当前用户session
                // 重新设置当前用户信息
                bool2 = setCurentLoginUser(request, userID, type); // 设置用户信息
                if (bool2 == false) {
                  response.sendRedirect(returnLoginUrl);
                  return false;
                } else {
                  return true;
                }
              } else { // 同一个用户，不作处理
                return true;
              }
            } else { // 用户类型不匹配，重新设置新的用户
              clearSessionUser(request); // 清空当前用户session
              // 重新设置当前用户信息
              bool2 = setCurentLoginUser(request, userID, type); // 设置用户信息
              if (bool2 == false) {
                response.sendRedirect(returnLoginUrl);
                return false;
              } else {
                return true;
              }
            }
          } else { // 用户类型为空，代表不是从栏目传值过来
            return true;
          }
          // return true;
        } else {
          // 未登录，返回登陆页面
          // 第一种情况是确实没有登录，跳转到登录页面
          if (!StringUtils.isNullValue(userID) && !StringUtils.isNullValue(type)) {
            // 进行登录
            setCurentLoginUser(request, userID, type); // 设置用户信息
            return true;
          } else { // 第二种情况是session失效
            response.sendRedirect(returnLoginUrl);
            return false;
          }
          // if (request.getHeader("x-requested-with") != null
          // && request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
          // response.setHeader("sessionstatus", "timeout");// 在响应头设置session状态
          // return false;
          // } else {
          // String returnUrl = request.getScheme() + "://"; // 请求协议 http 或 https
          // returnUrl += request.getHeader("host"); // 请求服务器
          // returnUrl += request.getRequestURI(); // 工程名
          // if (request.getQueryString() != null) {
          // returnUrl += "?" + request.getQueryString(); // 参数
          // }
          // response.sendRedirect(request.getContextPath() + returnLoginUrl + "?returnUrl="
          // + URLEncoder.encode(returnUrl, "UTF-8"));
          // return false;
          // }
        }
      } else {
        // 不需要登陆
        return true;
      }
    }
    return true;

  }

  /**
   * 设置当前用户信息
   * 
   * @param request
   * @param response
   * @param userID
   * @param type
   */
  private static boolean setCurentLoginUser(HttpServletRequest request, String userID,
      String type) {
    ICommonService commonService = null;
    boolean bool = false;
    switch (type) {
      case "s": // 代表是学生用户
        Student student = new Student();
        student.setXsid(Integer.parseInt(userID));
        commonService = (ICommonService) SpringUtil.getBean("commonService");
        Student currentLoginedStudent = commonService.queryStudentByEmployee(student);
        if (currentLoginedStudent == null) {
          bool = false;
        } else {
          bool = true;
          request.getSession().setMaxInactiveInterval(1800);
          request.getSession().setAttribute(Constant.LOGIN_CONSOLE_USER, currentLoginedStudent);
          request.getSession().setAttribute(Constant.LOGIN_USER_TYPE, Constant.USER_TYPE_STUDENT);
        }
        break;
      case "t": // 代表是老师用户
        UserEmployee user = new UserEmployee();
        user.setUid(Integer.parseInt(userID));
        commonService = (ICommonService) SpringUtil.getBean("commonService");
        UserEmployee currentLoginedUser = commonService.queryUserByEmployee(user);
        if (currentLoginedUser == null) {
          bool = false;
        } else {
          request.getSession().setMaxInactiveInterval(1800);
          request.getSession().setAttribute(Constant.LOGIN_CONSOLE_USER, currentLoginedUser);
          request.getSession().setAttribute(Constant.LOGIN_USER_TYPE, Constant.USER_TYPE_TEACHER);
          // 权限信息
          List<Priority> priorityList = commonService.queryUserByPriority(user);
          request.getSession().setAttribute("permisstionList", priorityList);
          bool = true;
        }
        break;
      default: // 代表非法
        bool = false;
        break;
    }
    return bool;
  }

  /**
   * 验证当前用户身份是否是当前用户
   * 
   * @param request
   * @param type
   * @return
   */
  private static boolean isValdateCurentLoginUser(HttpServletRequest request, String type,
      String userId) {
    boolean bool = false;
    switch (type) {
      case "s": // 代表是学生用户
        Student student = getSessionStudentUser(request);
        if (userId.equals(student.getXsid().toString())) {
          bool = true; // 表示当前用户是同一个用户
        } else {
          bool = false;
        }
        break;
      case "t": // 代表是老师用户
        UserEmployee userEmployee = getSessionUserEmployeeUser(request);
        if (userId.equals(userEmployee.getUid().toString())) {
          bool = true; // 表示当前用户是同一个用户
        } else {
          bool = false;
        }
        break;
      default:
        break;
    }
    return bool;
  }

  /**
   * 获得session学生用户信息
   * 
   * @param request
   * @return
   */
  private static Student getSessionStudentUser(HttpServletRequest request) {
    Student student = (Student) request.getSession().getAttribute(Constant.LOGIN_CONSOLE_USER);
    return student;
  }

  /**
   * 获得session教师用户信息
   * 
   * @param request
   * @return
   */
  private static UserEmployee getSessionUserEmployeeUser(HttpServletRequest request) {
    UserEmployee userEmployee =
        (UserEmployee) request.getSession().getAttribute(Constant.LOGIN_CONSOLE_USER);
    return userEmployee;
  }

  /**
   * 清空当前用户信息
   * 
   * @param request
   */
  private static void clearSessionUser(HttpServletRequest request) {
    if (request.getSession().getAttribute(Constant.LOGIN_CONSOLE_USER) != null) {
      request.getSession().removeAttribute(Constant.LOGIN_CONSOLE_USER);
      request.getSession().removeAttribute("permisstionList");
      request.getSession().removeAttribute(Constant.LOGIN_USER_TYPE);
    }
    // if (request.getSession().getAttribute(Constant.LOGIN_USER_TYPE) != null) {
    // request.getSession().removeAttribute(Constant.LOGIN_USER_TYPE);
    // }
  }

  // 验证Referer
  private static boolean verfityReferer(HttpServletRequest request) {
    // 从 HTTP 头中取得 Referer 值
    String referer = request.getHeader("Referer");
    // 判断 Referer 是否以 192.168.1.2004 开头
    String[] verfityRemoteUrls = Constant.VERFITY_REMOTE_URLS;
    boolean bool = false;
    if (verfityRemoteUrls.length >= 1) {
      for (String url : verfityRemoteUrls) {
        if ((referer != null) && (referer.trim().startsWith(url))) {
          bool = true;
          System.out.println("referer==" + referer);
          break;
        }
      }
    }
    System.out.println("bool==" + bool);
    return true;
  }

  /**
   * 根据请求地址获取token-key
   * 
   * @param request
   * @return
   */
  public static String getTokenKey(HttpServletRequest request) {
    String key = null;
    MessageDigest mDigest;
    try {
      // 摘要算法可以自己选择
      mDigest = MessageDigest.getInstance("MD5");
      byte[] result = mDigest.digest(request.getRequestURL().toString().getBytes());
      key = byteArrayToHex(result);
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    }
    return key;

  }

  /**
   * 下面这个函数用于将字节数组换成成16进制的字符串
   * 
   * @param byteArray
   * @return
   */

  public static String byteArrayToHex(byte[] byteArray) {
    // 首先初始化一个字符数组，用来存放每个16进制字符
    char[] hexDigits =
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    // new一个字符数组，这个就是用来组成结果字符串的（解释一下：一个byte是八位二进制，也就是2位十六进制字符（2的8次方等于16的2次方））
    char[] resultCharArray = new char[byteArray.length * 2];
    // 遍历字节数组，通过位运算（位运算效率高），转换成字符放到字符数组中去
    int index = 0;
    for (byte b : byteArray) {
      resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];

      resultCharArray[index++] = hexDigits[b & 0xf];
    }
    // 字符数组组合成字符串返回
    return new String(resultCharArray);
  }

  /**
   * 
   * 获取token-value并存储在session中
   * 
   */
  public static String getTokenValue(HttpServletRequest request) {
    String key = getTokenKey(request);
    Map<String, String> tokenMap = null;
    Object obj = request.getSession().getAttribute("tokenMap");
    if (obj == null) {
      tokenMap = new HashMap<String, String>();
      request.getSession().setAttribute("tokenMap", tokenMap);
    } else {
      tokenMap = (Map<String, String>) obj;
    }
    if (tokenMap.containsKey(key)) {
      return tokenMap.get(key);
    }
    String value = UUID.randomUUID().toString();// GUID实现可自行百度，其实弄个伪随机数也是可以的...
    tokenMap.put(key, value);
    return value;
  }

  /**
   * 
   * 验证token
   * 
   */
  public static boolean verifyToken(String key, String value, HttpServletRequest request) {
    boolean result = false;
    if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {// key或value只要有一个不存在就验证不通过
      return result;
    }
    if (request.getSession() != null) {
      Map<String, String> tokenMap =
          (Map<String, String>) request.getSession().getAttribute("tokenMap");
      if (value.equals(tokenMap.get(key))) {
        result = true;
        tokenMap.remove(key);// 成功一次就失效
      }
    }
    return result;

    // <form name="frm" action="/test/tokentest.htm" method="POST">
    //
    // <input type="hidden" name="token_key" value="<%=Token.getTokenKey(request) %>"/>
    //
    // <input type="hidden" name="token_value" value="<%=Token.getTokenValue(request) %>"/>
    //
    // ...
    //
    // </form>
  }


  public String getReturnLoginUrl() {
    return returnLoginUrl;
  }

  public void setReturnLoginUrl(String returnLoginUrl) {
    this.returnLoginUrl = returnLoginUrl;
  }

}
